package com.caigou.aop;

import com.caigou.bean.bid.entity.BidPrivilege;
import com.caigou.bean.cms.entity.UserBaseInfo;
import com.caigou.bean.cms.entity.UserPrivilege;
import com.caigou.bean.exam.entity.Users;
import com.caigou.enums.Constant;
import com.caigou.mapper.cms.UserBaseInfoMapper;
import com.caigou.mapper.exam.UsersMapper;
import com.caigou.security.utils.JwtTokenUtils;
import com.caigou.service.IUsersService;
import com.caigou.util.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Aspect
@Component
public class HttpRequestAspect {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserBaseInfoMapper userBaseInfoMapper;
    @Resource
    private UsersMapper usersMapper;
    @Autowired
    private IUsersService usersService;


    @Pointcut(value = "execution(public * com.caigou.controller.*.*(..))")
    public void verify() {
    }

    @Before("verify()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String url = request.getRequestURL().toString();
//            String[] split = url.split("/");
//            String urlField = split[split.length - 1];
            if (url.endsWith("verification") ||  url.endsWith("/register/query") ||url.endsWith("/binding/wx/auth")
                    ||url.endsWith("/wxUserInfo")  ||url.endsWith("/signOut")  ||url.endsWith("/buildHtml")   ||url.endsWith("/buildFragment") || url.endsWith("/loadUserIsSubmit")) {
                return;
            }

            String authorizationHeader = request.getHeader("Authorization");
            if (!StringUtils.isEmpty(authorizationHeader)) {
                String redisToken = stringRedisTemplate.opsForValue().get(authorizationHeader);
                if (!StringUtils.isEmpty(redisToken))  {
                    String decodedData = null; //传入密文和私钥,得到明文
                    try {
                        decodedData = RSAUtils.privateDecrypt(authorizationHeader, RSAUtils.getPrivateKey(JwtTokenUtils.PRIVATE_KEY));
                    } catch (NoSuchAlgorithmException e) {
                        log.error(e.getMessage(), e);
                    } catch (InvalidKeySpecException e) {
                        log.error(e.getMessage(), e);
                    }
                    if (!StringUtils.isEmpty(decodedData)) {
                        String[] strArray = decodedData.split("_");
                        String userId = strArray[2];
                        //去员工表查询校验是否为员工   员工设置token两个小时   前台用户为永久
                        UserBaseInfo baseInfoByUserId = userBaseInfoMapper.findUserBaseInfoByUserId(userId);
                        //给用户设置权限
                        ArrayList<GrantedAuthority> authorities = new ArrayList<>();

                        //给用户设置权限
                        List<BidPrivilege> bidPrivileges = usersService.findBidPrivilegesByUserId(userId, Constant.UNSTRUCTURED_DATA);
                        if (!CollectionUtils.isEmpty(bidPrivileges)) {
                            bidPrivileges.stream().forEach(privilege -> {
                                authorities.add(new SimpleGrantedAuthority(privilege.getPrivilegeCode()));
                            });
                        }


                        List<UserPrivilege> privileges = usersService.findPrivilegeCodesByUserId(userId);
                        if (!CollectionUtils.isEmpty(privileges)) {
                            privileges.forEach(privilege -> {
                                authorities.add(new SimpleGrantedAuthority(privilege.getPrivilegeCode()));
                            });
                        }
                        authorities.add(new SimpleGrantedAuthority("user_login"));
                        //由底层实现来查询寻用户信息.并判断密码是否正确

                        Users users = usersMapper.findUserByUserId(userId);
                        String token = JwtTokenUtils.createToken(users.getTel(), userId,
                                authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()), true);
    //                    String token = JwtTokenUtils.createToken(users.getTel(), users.getUserid(), Collections.singletonList("user_login"), true);
                        if (baseInfoByUserId != null) {
                            try {
                                if (!StringUtils.isEmpty(token)) {
                                    stringRedisTemplate.opsForValue().set(authorizationHeader, JwtTokenUtils.TOKEN_PREFIX + token, JwtTokenUtils.TOKEN_LIFE_TIME, TimeUnit.HOURS);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                        }else {
                            //非员工
                            if (!StringUtils.isEmpty(token)) {
                                stringRedisTemplate.opsForValue().set(authorizationHeader, JwtTokenUtils.TOKEN_PREFIX + token, 900000, TimeUnit.DAYS);
                            }
                        }
                    }
                }
            }
        }


        //Class.Method
        log.debug("CLass.Method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + "()");

        //Args
        log.debug("Args={}", joinPoint.getArgs());

    }


}
